package com.neusoft.hifly.commons.lang;

import java.sql.Timestamp;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;

/**
 * Title: 核心类库
 * <p>
 * Description: Java 8 日期转换类
 * <p>
 * java.util.Date和SimpleDateFormatter都不是线程安全的，而LocalDate和LocalTime和最基本的String一样，是不变类型，不但线程安全，而且不能修改。
 * <p>
 * Java 8开始，明确了日期时间概念，例如：瞬时（instant）、 长短（duration）、日期、时间、时区和周期。
 * <p>
 * Java 8 'uuuu'用于年份，而不是'yyyy'。在Java 8中，“ yyyy”表示“时代”（BC或AD）。
 * <p>
 * Instant：瞬时实例。
 * <p>
 * LocalDate：本地日期，不包含具体时间 例如：2014-01-14 可以用来记录生日、纪念日、加盟日等。
 * <p>
 * LocalTime：本地时间，不包含日期。
 * <p>
 * LocalDateTime：组合了日期和时间，但不包含时差和时区信息。
 * <p>
 * ZonedDateTime：最完整的日期时间，包含时区和相对UTC或格林威治的时差。
 * <p>
 * 例如，我们使用LocalDate代替Date，使用DateTimeFormatter代替SimpleDateFormat，如下所示:
 * <p>
 * String DateNow = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // 当前日期和时间
 * System.out.println(DateNow);
 * <p>
 * 这样就避免了SimpleDateFormat的线程不安全问题
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
public class LocalDateUtil {
	/**
	 * 年-月-日 时:分:秒:毫秒 最全版
	 */
	public final static String DEFAULT_PATTERN_DATETIME_FULL = "uuuu-MM-dd HH:mm:ss.SSS";

	/**
	 * 年-月-日 时:分:秒:毫秒 中文版
	 */
	public final static String DEFAULT_PATTERN_DATETIME_FULL_CHINESE = "uuuu年MM月dd日 HH:mm:ss.SSS";

	/**
	 * 年-月-日 时:分:秒:毫秒 中文版全
	 */
	public final static String DEFAULT_PATTERN_DATETIME_CHINESE_FULL = "uuuu年MM月dd日 HH时mm分ss秒SSS毫秒";

	/**
	 * 年-月-日 时:分:秒 标准样式
	 */
	public final static String DEFAULT_PATTERN_DATETIME = "uuuu-MM-dd HH:mm:ss";

	/**
	 * 年-月-日 时:分:秒 中文版1
	 */
	public final static String DEFAULT_PATTERN_DATETIME_CHINESE_ONE = "uuuu年MM月dd日 HH:mm:ss";

	/**
	 * 年-月-日 时:分:秒 中文版2
	 */
	public final static String DEFAULT_PATTERN_DATETIME_CHINESE_TWO = "uuuu年MM月dd日 HH时mm分ss秒";

	/**
	 * 年-月-日
	 */
	public final static String DEFAULT_PATTERN_DATE = "uuuu-MM-dd";

	/**
	 * 年-月-日 中文版
	 */
	public final static String DEFAULT_PATTERN_DATE_CHINESE = "uuuu年MM月dd日";

	/**
	 * 年-月 中文版
	 */
	public final static String DEFAULT_PATTERN_DATE_YEAR_MONTH_CHINESE = "uuuu年MM月";

	/**
	 * 月-日
	 */
	public final static String DEFAULT_PATTERN_MONTH = "MM-dd";

	/**
	 * 日
	 */
	public final static String DEFAULT_PATTERN_DAY = "dd";

	/**
	 * 时:分:秒
	 */
	public final static String DEFAULT_PATTERN_TIME = "HH:mm:ss";

	/**
	 * 年月日时分秒毫秒 紧凑版
	 */
	public final static String DEFAULT_PATTERN_DATETIME_SIMPLE_FULL = "uuuuMMddHHmmssSSS";

	/**
	 * 年月日时分秒
	 */
	public final static String DEFAULT_PATTERN_DATETIME_SIMPLE = "uuuuMMddHHmmss";

	/**
	 * 年月日
	 */
	public final static String DEFAULT_PATTERN_DATETIME_DATE = "uuuuMMdd";

	/**
	 * 月日
	 */
	public final static String DEFAULT_PATTERN_DATETIME_MONTH = "MMdd";

	/**
	 * 时分秒毫秒
	 */
	public final static String DEFAULT_PATTERN_DATETIME_TIME_FULL = "HHmmss";

	/**
	 * 统一的页面显示时间：yyyy-MM-dd HH:mm
	 *
	 * @param dateTime
	 *            日期时间
	 * @return 格式化后的日期
	 */
	public static String showTime(final LocalDateTime dateTime) {
		if (dateTime == null) {
			return "";
		}
		// 获取当前年
		final int nowYear = LocalDate.now().getYear();

		final int year = dateTime.getYear();

		if (nowYear == year) {
			// 当前年的
			return LocalDateUtil.dateTimeToStr(dateTime, "MM-dd HH:mm");
		} else {
			// 更远的日期格式
			return LocalDateUtil.dateTimeToStr(dateTime, "yyyy-MM-dd HH:mm");
		}
	}

	/**
	 * 校验两个时间大小
	 *
	 * @param start
	 *            开始时间
	 * @param end
	 *            结束时间
	 * @return 大于：true，小于：false
	 */
	public static boolean checkTime(final String start, final String end) {
		return checkTime(strToDateTime(start), strToDateTime(end));
	}

	/**
	 * 校验两个时间大小
	 *
	 * @param start
	 *            开始时间
	 * @param end
	 *            结束时间
	 * @return 大于：true，小于：false
	 */
	public static boolean checkTime(final LocalDateTime start, final String end) {
		return checkTime(start, strToDateTime(end));
	}

	/**
	 * 校验两个时间大小
	 *
	 * @param start
	 *            开始时间
	 * @param end
	 *            结束时间
	 * @return 大于：true，小于：false
	 */
	public static boolean checkTime(final String start, final LocalDateTime end) {
		return checkTime(strToDateTime(start), end);
	}

	/**
	 * 校验两个时间大小
	 *
	 * @param start
	 *            开始时间
	 * @param end
	 *            结束时间
	 * @return 大于：true，小于：false
	 */
	public static boolean checkTime(final LocalDateTime start, final LocalDateTime end) {
		if (start == null && end == null) {
			return false;
		}
		if (start == null && end != null) {
			return false;
		}
		if (start != null && end == null) {
			return true;
		}
		if ((LocalDateUtil.getMillis(start) - LocalDateUtil.getMillis(end)) > 0) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 校验两个日期大小
	 *
	 * @param start
	 *            开始日期
	 * @param end
	 *            结束日期
	 * @return 大于：true，小于：false
	 */
	public static boolean checkDate(final String start, final String end) {
		return checkDate(strToDate(start), strToDate(end));
	}

	/**
	 * 校验两个日期大小
	 *
	 * @param start
	 *            开始日期
	 * @param end
	 *            结束日期
	 * @return 大于：true，小于：false
	 */
	public static boolean checkDate(final LocalDate start, final LocalDate end) {
		if (start == null && end == null) {
			return false;
		}
		if (start == null && end != null) {
			return false;
		}
		if (start != null && end == null) {
			return true;
		}
		if ((LocalDateUtil.getMillis(end) - LocalDateUtil.getMillis(start)) > 0) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * LocalDate转Date
	 *
	 * @param localDate
	 *            日期
	 * @return 日期
	 */
	public static Date localDate2Date(final LocalDate localDate) {
		if (null == localDate) {
			return null;
		}
		final ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
		return Date.from(zonedDateTime.toInstant());
	}

	/**
	 * Date转LocalDate
	 *
	 * @param date
	 *            日期
	 * @return 日期
	 */
	public static LocalDate date2LocalDate(final Date date) {
		if (null == date) {
			return null;
		}
		return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
	}

	/**
	 * 格式化年月日为字符串
	 *
	 * @param localDate
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @return String 返回格式化的日期
	 */
	public static String dateToStr(final LocalDate localDate, final String pattern) {
		if (null == localDate) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		return LocalDateUtil.getDateFormat(localDate, dateTimeFormatter);
	}

	/**
	 * 格式化年月日为字符串
	 *
	 * @param localDate
	 *            传入需要格式化的日期
	 * @return String 返回格式化的日期
	 */
	public static String dateToStr(final LocalDate localDate) {
		if (null == localDate) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil
				.getDateTimeFormatter(LocalDateUtil.DEFAULT_PATTERN_DATE);
		return LocalDateUtil.getDateFormat(localDate, dateTimeFormatter);
	}

	/**
	 * 时区格式化年月日为字符串
	 *
	 * @param localDate
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @param locale
	 *            国际时区 Locale.CHINA
	 * @return String 返回格式化的日期
	 */
	public static String dateToStr(final LocalDate localDate, final String pattern, final Locale locale) {
		if (null == localDate) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern, locale);
		return LocalDateUtil.getDateFormat(localDate, dateTimeFormatter);
	}

	/**
	 * 格式化年月日时分秒为字符串
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @return String 返回格式化的日期
	 */
	public static String dateTimeToStr(final LocalDateTime localDateTime) {
		if (null == localDateTime) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil
				.getDateTimeFormatter(LocalDateUtil.DEFAULT_PATTERN_DATETIME);
		return LocalDateUtil.getDateTimeFormat(localDateTime, dateTimeFormatter);
	}

	/**
	 * 格式化年月日时分秒为字符串
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @return String 返回格式化的日期
	 */
	public static String dateTimeToStr(final LocalDateTime localDateTime, final String pattern) {
		if (null == localDateTime) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		return LocalDateUtil.getDateTimeFormat(localDateTime, dateTimeFormatter);
	}

	/**
	 * 时区格式化年月日时分秒为字符串
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @param locale
	 *            国际时区 Locale.CHINA
	 * @return String 返回格式化的日期
	 */
	public static String dateTimeToStr(final LocalDateTime localDateTime, final String pattern, final Locale locale) {
		if (null == localDateTime) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern, locale);
		return LocalDateUtil.getDateTimeFormat(localDateTime, dateTimeFormatter);
	}

	/**
	 * 格式化时分秒为字符串
	 *
	 * @param localTime
	 *            传入需要格式化的时间
	 * @param pattern
	 *            需要格式化的格式
	 * @return String 返回格式化的时间
	 */
	public static String timeToStr(final LocalTime localTime, final String pattern) {
		if (null == localTime) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		return LocalDateUtil.getDateTimeFormat(localTime, dateTimeFormatter);
	}

	/**
	 * LocalDate格式化日期为日期格式
	 *
	 * @param localDate
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @return String 返回格式化的日期
	 */
	public static LocalDate strToDate(final String localDate, final String pattern) {
		if (StringUtils.isEmpty(localDate)) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		return LocalDateUtil.parse(localDate, dateTimeFormatter);
	}

	/**
	 * LocalDate格式化日期为日期格式
	 *
	 * @param localDate
	 *            传入需要格式化的日期
	 * @return String 返回格式化的日期
	 */
	public static LocalDate strToDate(final String localDate) {
		if (StringUtils.isEmpty(localDate)) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil
				.getDateTimeFormatter(LocalDateUtil.DEFAULT_PATTERN_DATE);
		return LocalDateUtil.parse(localDate, dateTimeFormatter);
	}

	/**
	 * localDateTime格式化日期为日期格式
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @return String 返回格式化的日期
	 */
	public static LocalDateTime strToDateTime(final String localDateTime, final String pattern) {
		if (StringUtils.isEmpty(localDateTime)) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		return LocalDateUtil.getDateTimeParse(localDateTime, dateTimeFormatter);
	}

	/**
	 * localDateTime格式化日期为日期格式
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @return String 返回格式化的日期
	 */
	public static LocalDateTime strToDateTime(final String localDateTime) {
		if (StringUtils.isEmpty(localDateTime)) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil
				.getDateTimeFormatter(LocalDateUtil.DEFAULT_PATTERN_DATETIME);
		return LocalDateUtil.getDateTimeParse(localDateTime, dateTimeFormatter);
	}

	/**
	 * java.sql.Timestamp 转 java.time.LocalDateTime
	 *
	 * @param timestamp
	 *            传入需要格式化的日期
	 * @return LocalDateTime日期
	 */
	public static LocalDateTime timestampToDateTime(final Timestamp timestamp) {
		if (timestamp == null) {
			return null;
		}
		return timestamp.toLocalDateTime();
	}

	/**
	 * java.time.LocalDateTime 转 java.sql.Timestamp
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @return Timestamp日期
	 */
	public static Timestamp dateTimeToTimestamp(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		return Timestamp.valueOf(localDateTime);
	}

	/**
	 * 日期格式化日期，转化为日期格式 localDate 转 LocalDate
	 *
	 * @param localDate
	 *            传入的日期
	 * @param pattern
	 *            转化的格式
	 * @return 返回结果 LocalDate
	 */
	public static LocalDate formatter(final LocalDate localDate, final String pattern) {
		if (localDate == null) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		final String formatterDateTime = LocalDateUtil.getDateFormat(localDate, dateTimeFormatter);
		return LocalDateUtil.parse(formatterDateTime);
	}

	/**
	 * 日期格式化日期，转化为日期格式 localDateTime 转 localDateTime
	 *
	 * @param localDateTime
	 *            传入需要格式化的日期
	 * @param pattern
	 *            需要格式化的格式
	 * @return String 返回格式化的日期
	 */
	public static LocalDateTime formatter(final LocalDateTime localDateTime, final String pattern) {
		if (localDateTime == null) {
			return null;
		}
		final DateTimeFormatter dateTimeFormatter = LocalDateUtil.getDateTimeFormatter(pattern);
		final String formatterDateTime = LocalDateUtil.getDateTimeString(localDateTime, dateTimeFormatter);
		return LocalDateUtil.getDateTimeParse(formatterDateTime, dateTimeFormatter);
	}

	/**
	 * 转换毫秒数
	 *
	 * @param mss
	 *            要转换的毫秒数
	 * @return 该毫秒数转换为 * days * hours * minutes * seconds 后的格式
	 */
	public static String formatDuring(final long mss) {
		final StringBuffer result = new StringBuffer("");
		if (mss < 1000) {
			// 不到1秒的
			result.append(mss + "毫秒");
		} else {
			// 大于1秒的

			final long days = mss / (1000 * 60 * 60 * 24);
			final long hours = (mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
			final long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60);
			final long seconds = (mss % (1000 * 60)) / 1000;

			if (days >= 1) {
				result.append(days + "天");
			}
			if (hours >= 1) {
				result.append(hours + "小时");
			}
			if (minutes >= 1) {
				result.append(minutes + "分");
			}
			result.append(seconds + "秒");
		}
		return result.toString();
	}

	/**
	 * 获取本周开始时间
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回本周开始时间
	 */
	public static LocalDateTime getTodayFirstOfWeek(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		final TemporalAdjuster temporalAdjuster = LocalDateUtil.getFirstTemporalAdjuster();
		return localDateTime.with(temporalAdjuster);
	}

	/**
	 * 获取本周结束时间
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 本周结束时间
	 */
	public static LocalDateTime getTodayLastOfWeek(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		final TemporalAdjuster temporalAdjuster = LocalDateUtil.getLastTemporalAdjuster();
		return localDateTime.with(temporalAdjuster);
	}

	/**
	 * 获取天的开始时间
	 *
	 * @param day
	 *            0 今天 1 明天 -1 昨天
	 * @return 开始时间
	 */
	public static LocalDateTime getTodayStartTime(final int day) {
		return LocalDate.now().plusDays(day).atStartOfDay();
	}

	/**
	 * 获取某月的开始时间
	 *
	 * @param month
	 *            0 本月 1 下月 -1 上月
	 * @return 月开始的时间
	 */
	public static LocalDate getMonthStartTime(final int month) {
		return LocalDate.now().plusMonths(month).with(TemporalAdjusters.firstDayOfMonth());
	}

	/**
	 * 获取某年的开始时间
	 *
	 * @param year
	 *            0 今年 1 明年 -1 前年
	 * @return 年的开始时间
	 */
	public static LocalDate getYearStartTime(final int year) {
		return LocalDate.now().plusYears(year).with(TemporalAdjusters.firstDayOfYear());
	}

	/**
	 * 获取某天的结束时间
	 *
	 * @return 天的结束时间 ZoneId.systemDefault()系统默认时区，如果需要改变时区使用ZoneId.of("时区")
	 */
	public static LocalDateTime getTodayEndTime() {
		return LocalDateTime.of(LocalDate.now(ZoneId.systemDefault()), LocalTime.MIDNIGHT);
	}

	/**
	 * 获取某月的结束时间
	 *
	 * @param day
	 *            0 本月 1 下月 -1 上月
	 * @return 月的结束时间
	 */
	public static LocalDate getMonthEndTime(final int day) {
		return LocalDate.now().plusDays(day).with(TemporalAdjusters.lastDayOfMonth());
	}

	/**
	 * 获取某年的结束时间
	 *
	 * @param year
	 *            0 今年 1 明年 -1 前年
	 * @return 年的结束时间
	 */
	public static LocalDate getYearEndTime(final int year) {
		return LocalDate.now().plusYears(year).with(TemporalAdjusters.lastDayOfYear());
	}

	/**
	 * 获取今天中午的时间
	 *
	 * @return 今天中午的时间
	 */
	public static LocalDateTime getTodayNoonTime() {
		return LocalDateTime.of(LocalDate.now(ZoneId.systemDefault()), LocalTime.NOON);
	}

	/**
	 * 在日期上增加数个整天
	 *
	 * @param instant
	 *            输入日期
	 * @param day
	 *            增加或减少的天数
	 * @return 增加或减少后的日期
	 */
	public static LocalDateTime addDays(final Instant instant, final int day) {
		if (instant == null) {
			return null;
		}
		final LocalDateTime localDateAboutInstant = LocalDateUtil.getLocalDateAboutInstant(instant);
		return localDateAboutInstant.plusDays(day);
	}

	/**
	 * 在日期上增加几月
	 *
	 * @param instant
	 *            输入日期
	 * @param months
	 *            增加的月数
	 * @return 增加后的日期
	 */
	public static LocalDateTime addMonths(final Instant instant, final int months) {
		if (instant == null) {
			return null;
		}
		final LocalDateTime localDateAboutInstant = LocalDateUtil.getLocalDateAboutInstant(instant);
		return localDateAboutInstant.plusMonths(months);
	}

	/**
	 * 在日期上增加几周
	 *
	 * @param instant
	 *            输入日期
	 * @param weeks
	 *            增加的周数
	 * @return 增加后的日期
	 */
	public static LocalDateTime addWeeks(final Instant instant, final int weeks) {
		if (instant == null) {
			return null;
		}
		final LocalDateTime localDateAboutInstant = LocalDateUtil.getLocalDateAboutInstant(instant);
		return localDateAboutInstant.plusWeeks(weeks);
	}

	/**
	 * 在日期上增加/减少（负数）数个小时
	 *
	 * @param instant
	 *            输入时间
	 * @param hours
	 *            增加/减少的小时数
	 * @return 增加/减少小时后的日期
	 */
	public static LocalDateTime addHours(final Instant instant, final int hours) {
		if (instant == null) {
			return null;
		}
		final LocalDateTime localDateAboutInstant = LocalDateUtil.getLocalDateAboutInstant(instant);
		return localDateAboutInstant.plusHours(hours);
	}

	/**
	 * 在日期上增加/减少数个分钟
	 *
	 * @param instant
	 *            输入时间
	 * @param minutes
	 *            增加/减少的分钟数
	 * @return 增加/减少分钟后的日期
	 */
	public static LocalDateTime addMinutes(final Instant instant, final int minutes) {
		if (instant == null) {
			return null;
		}
		final LocalDateTime localDateAboutInstant = LocalDateUtil.getLocalDateAboutInstant(instant);
		return localDateAboutInstant.plusMinutes(minutes);
	}

	/**
	 * 得到两个日期时间的差额(毫秒)
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return 两个时间相差多少秒
	 */
	public static long differenceDateMillis(final LocalDateTime startTime, final LocalDateTime endTime) {
		if (startTime == null || endTime == null) {
			return -1;
		}
		final Duration between = Duration.between(startTime, endTime);
		return between.toMillis();
	}

	/**
	 * 得到两个日期时间的差额(分)
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return 两个时间相差多少分
	 */
	public static long differenceDateMinutes(final LocalDateTime startTime, final LocalDateTime endTime) {
		if (startTime == null || endTime == null) {
			return -1;
		}
		final Duration between = Duration.between(startTime, endTime);
		return between.toMinutes();
	}

	/**
	 * 毫秒转小时
	 * 
	 * @param millis
	 *            毫秒
	 * @return 小时
	 */
	public static long millisToHour(long millis) {
		return millis / 1000 / 60 / 60;
	}

	/**
	 * 得到两个日期时间的差额(小时)
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return 两个时间相差多少小时
	 */
	public static long differenceDateHours(final LocalDateTime startTime, final LocalDateTime endTime) {
		if (startTime == null || endTime == null) {
			return -1;
		}
		final Duration between = Duration.between(startTime, endTime);
		return between.toHours();
	}

	/**
	 * 得到两个日期时间的差额(天)
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return 两个时间相差多少天
	 */
	public static long differenceDateDays(final LocalDateTime startTime, final LocalDateTime endTime) {
		if (startTime == null || endTime == null) {
			return -1;
		}
		final Duration between = Duration.between(startTime, endTime);
		return between.toDays();
	}

	/**
	 * 获取指定日期的月份
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的月份
	 */
	public static int getMonthAboutLocalTime(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return -1;
		}
		final Month month = localDateTime.getMonth();
		return LocalDateUtil.getMonth(month);
	}

	/**
	 * 获取指定日期的年份
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的年份
	 */
	public static int getYearAboutLocalTime(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return -1;
		}
		return localDateTime.getYear();
	}

	/**
	 * 获取指定日期的天数
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的天数
	 */
	public static int getDayAboutLocalTime(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return -1;
		}
		return localDateTime.getDayOfMonth();
	}

	/**
	 * 获取指定日期的星期
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的星期
	 */
	public static int getWeekDayAboutLocalTime(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return -1;
		}
		return localDateTime.getDayOfWeek().getValue();
	}

	/**
	 * 获取指定日期的时间
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的时间
	 */
	public static int getHouryAboutLocalTime(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return -1;
		}
		return localDateTime.getHour();
	}

	/**
	 * 获取指定日期的所在月的最后一天
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的时间
	 */
	public static int getLateDayFromMonth(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return -1;
		}
		return localDateTime.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
	}

	/**
	 * 获取指定日期的所在月的第一天
	 *
	 * @param localDateTime
	 *            输入日期
	 * @return 返回指定日期的时间
	 */
	public static LocalDateTime getFirstDayFromMonth(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		return localDateTime.with(TemporalAdjusters.firstDayOfMonth());
	}

	/**
	 * 获取到指定日期一个月有几天
	 *
	 * @param instant
	 *            输入日期
	 * @return 天数
	 */
	public static int getDayCountOfMonth(final Instant instant) {
		if (instant == null) {
			return -1;
		}
		final LocalDateTime localDateTime = LocalDateUtil.instantToDateTime(instant);
		final LocalDateTime startTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth());
		final LocalDateTime endTime = localDateTime.with(TemporalAdjusters.lastDayOfMonth());
		final Duration between = Duration.between(startTime, endTime);
		return (int) between.toDays() + 1;
	}

	/**
	 * 当前时间10位毫秒数
	 *
	 * @return 10位秒
	 */
	public static long getNowOfSecond() {
		final LocalDateTime localDateTime = LocalDateTime.now();
		return LocalDateUtil.dateTimeToInstant(localDateTime).plusMillis(TimeUnit.HOURS.toMillis(8)).getEpochSecond();
	}

	/**
	 * 当前时间13位毫秒数
	 *
	 * @return 13位毫秒数
	 */
	public static long getNowOfMillion() {
		final LocalDateTime localDateTime = LocalDateTime.now();
		return LocalDateUtil.dateTimeToInstant(localDateTime).toEpochMilli();
	}

	/**
	 * 当前时间13位毫秒数
	 *
	 * @return 13位毫秒数
	 */
	public static long getNowOfMillions() {
		final LocalDateTime localDateTime = LocalDateTime.now();
		return LocalDateUtil.dateTimeToInstant(localDateTime).plusMillis(TimeUnit.HOURS.toMillis(8)).toEpochMilli();
	}

	/**
	 * LocalDateTime 转化为 Instant
	 *
	 * @param localDateTime
	 *            输入的时间
	 * @return Instant的日期类型
	 */
	public static Instant dateTimeToInstant(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		return localDateTime.atZone(ZoneId.systemDefault()).toInstant();
	}

	/**
	 * LocalDateTime 转化为 LocalDate
	 *
	 * @param localDateTime
	 *            输入的时间
	 * @return LocalDate的日期类型
	 */
	public static LocalDate dateTimeToDate(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		return localDateTime.toLocalDate();
	}

	/**
	 * LocalDate 转化为 LocalDateTime
	 *
	 * @param localDate
	 *            输入的时间
	 * @return LocalDateTime的日期类型
	 */
	public static LocalDateTime dataToDateTime(final LocalDate localDate) {
		if (localDate == null) {
			return null;
		}
		return localDate.atStartOfDay(ZoneOffset.ofHours(8)).toLocalDateTime();
	}

	/**
	 * instant 转化为 LocalDateTime
	 *
	 * @param instant
	 *            输入的时间
	 * @return LocalDateTime的日期类型
	 */
	public static LocalDateTime instantToDateTime(final Instant instant) {
		if (instant == null) {
			return null;
		}
		return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
	}

	/**
	 * instant 转化为 LocalDate
	 *
	 * @param instant
	 *            输入的时间
	 * @return LocalDate的日期类型
	 */
	public static LocalDate instantToDate(final Instant instant) {
		if (instant == null) {
			return null;
		}
		return instant.atZone(ZoneOffset.ofHours(8)).toLocalDate();
	}

	/**
	 * 获取本周的周一日期
	 *
	 * @return 获取本周的周一日期
	 */
	public static LocalDateTime getMondayThisWeek() {
		final LocalDateTime todayFirstOfWeek = LocalDateUtil.getTodayFirstOfWeek(LocalDateUtil.getTodayStartTime(0));
		return todayFirstOfWeek.with(LocalDateUtil.getFirstTemporalAdjuster());
	}

	/**
	 * 获取本周的周日日期
	 *
	 * @return 获取本周的周日日期
	 */
	public static LocalDateTime getSundayThisWeek() {
		final LocalDateTime todayFirstOfWeek = LocalDateUtil.getTodayLastOfWeek(LocalDateUtil.getTodayStartTime(0));
		return todayFirstOfWeek.with(LocalDateUtil.getFirstTemporalAdjuster());
	}

	/**
	 * 取得指定日期的前一天
	 *
	 * @param localDateTime
	 *            指定日期
	 * @return 指定日期的前一天
	 */
	public static LocalDateTime getPreviousDay(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		return LocalDateUtil.addDays(LocalDateUtil.dateTimeToInstant(localDateTime), -1);
	}

	/**
	 * 取得指定日期的前一天
	 *
	 * @param localDateTime
	 *            指定日期
	 * @return 指定日期的前一天
	 */
	public static LocalDate getPreviousDay(final LocalDate localDate) {
		if (localDate == null) {
			return null;
		}
		return LocalDateUtil.dateTimeToDate(
				LocalDateUtil.addDays(LocalDateUtil.dateTimeToInstant(LocalDateUtil.dataToDateTime(localDate)), -1));
	}

	/**
	 * 获取上周周一的日期
	 *
	 * @return 获取上周周一的日期
	 */
	public static LocalDateTime getMondayPreviousWeek() {
		return LocalDateUtil.getMondayThisWeek().minusDays(7);
	}

	/**
	 * 获取上周周日的日期
	 *
	 * @return 获取上周周日的日期
	 */
	public static LocalDateTime getSundayPreviousWeek() {
		return LocalDateUtil.getSundayThisWeek().minusDays(8);
	}

	/**
	 * LocalDate转时间戳
	 *
	 * @param localDate
	 *            时间输入
	 * @return 时间戳
	 */
	public static Long getMillis(final LocalDate localDate) {
		if (localDate == null) {
			return null;
		}
		return localDate.atStartOfDay(ZoneOffset.ofHours(8)).toInstant().toEpochMilli();
	}

	/**
	 * LocalDateTime转时间戳
	 *
	 * @param localDateTime
	 *            时间输入
	 * @return 时间戳
	 */
	public static Long getMillis(final LocalDateTime localDateTime) {
		if (localDateTime == null) {
			return null;
		}
		return localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
	}

	/**
	 * 毫秒值转LocalDate
	 *
	 * @param timeStamp
	 *            时间戳毫秒值
	 * @return LocalDate
	 */
	public static LocalDate getMillisToDate(final long timeStamp) {
		return Instant.ofEpochMilli(timeStamp).atZone(ZoneOffset.ofHours(8)).toLocalDate();
	}

	/**
	 * 毫秒值转LocalDateTime
	 *
	 * @param timeStamp
	 *            时间戳毫秒值
	 * @return LocalDateTime
	 */
	public static LocalDateTime getMillisToDateTime(final long timeStamp) {
		return Instant.ofEpochMilli(timeStamp).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
	}

	/**
	 * 毫秒值加一年后的毫秒值
	 *
	 * @param original
	 *            毫秒值
	 * @return 毫秒值
	 */
	public static long getNextYear(final long original) {
		final LocalDateTime millisToLocalDateTime = LocalDateUtil.getMillisToDateTime(original);
		return millisToLocalDateTime.minus(1, ChronoUnit.YEARS).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
	}

	/**
	 * 获取LocalDate转化为字符串
	 *
	 * @param formatterDateTime
	 *            需要转化的数据
	 * @return LocalDate
	 */
	private static LocalDate parse(final String formatterDateTime) {
		return LocalDate.parse(formatterDateTime);
	}

	/**
	 * 获取LocalDate按要求转化为字符串
	 *
	 * @param formatterDateTime
	 *            需要转化的数据
	 * @param dateTimeFormatter
	 *            格式化
	 * @return LocalDate
	 */
	private static LocalDate parse(final String formatterDateTime, final DateTimeFormatter dateTimeFormatter) {
		return LocalDate.parse(formatterDateTime, dateTimeFormatter);
	}

	/**
	 * 获取LocalDateTime按照要求转化为字符串
	 *
	 * @param localDateTime
	 *            需要转化的数据
	 * @param dateTimeFormatter
	 *            转化的格式
	 * @return 返回结果
	 */
	private static String getDateTimeFormat(final LocalDateTime localDateTime,
			final DateTimeFormatter dateTimeFormatter) {
		return localDateTime.format(dateTimeFormatter);
	}

	/**
	 * 获取LocalTime按照要求转化为字符串
	 *
	 * @param localTime
	 *            需要转化的数据
	 * @param dateTimeFormatter
	 *            转化的格式
	 * @return 返回结果
	 */
	private static String getDateTimeFormat(final LocalTime localTime, final DateTimeFormatter dateTimeFormatter) {
		return localTime.format(dateTimeFormatter);
	}

	/**
	 * 获取数据按照国际标准转化的值
	 *
	 * @param pattern
	 *            需要转化的数据
	 * @param locale
	 *            传入国际时间
	 * @return 返回格式结果
	 */
	private static DateTimeFormatter getDateTimeFormatter(final String pattern, final Locale locale) {
		return DateTimeFormatter.ofPattern(pattern, locale);
	}

	/**
	 * 获取localDateTime按照国际标准转化的值
	 *
	 * @param localDateTime
	 *            需要转化的数据
	 * @param dateTimeFormatter
	 *            格式化
	 * @return 返回 LocalDateTime
	 */
	private static LocalDateTime getDateTimeParse(final String localDateTime,
			final DateTimeFormatter dateTimeFormatter) {
		return LocalDateTime.parse(localDateTime, dateTimeFormatter);
	}

	/**
	 * 获取LocalDate按照要求转化为字符串
	 *
	 * @param localDate
	 *            需要转化的数据
	 * @param dateTimeFormatter
	 *            转化的格式
	 * @return 转化后返回字符串
	 */
	private static String getDateFormat(final LocalDate localDate, final DateTimeFormatter dateTimeFormatter) {
		return dateTimeFormatter.format(localDate);
	}

	/**
	 * 获取格式化的结果
	 *
	 * @param pattern
	 *            传入的格式
	 * @return 返回格式化结果
	 */
	private static DateTimeFormatter getDateTimeFormatter(String pattern) {
		if (StringUtils.isEmpty(pattern)) {
			pattern = LocalDateUtil.DEFAULT_PATTERN_DATETIME;
		}
		return DateTimeFormatter.ofPattern(pattern);
	}

	/**
	 * 获取格式化LocalDateTime结果
	 *
	 * @param localDateTime
	 *            传入的数据
	 * @param dateTimeFormatter
	 *            格式化的结果
	 * @return 返回字符串
	 */
	private static String getDateTimeString(final LocalDateTime localDateTime,
			final DateTimeFormatter dateTimeFormatter) {
		return dateTimeFormatter.format(localDateTime);
	}

	/**
	 * 获取instant 转化的日期格式
	 *
	 * @param instant
	 *            DK8 代替Date使用的类
	 * @return 时间格式
	 */
	private static LocalDateTime getLocalDateAboutInstant(final Instant instant) {
		return LocalDateUtil.instantToDateTime(instant);
	}

	/**
	 * 本周开始时间
	 *
	 * @return 返回本周开始时间
	 */
	private static TemporalAdjuster getFirstTemporalAdjuster() {
		return TemporalAdjusters.ofDateAdjuster(
				localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
	}

	/**
	 * 本周结束时间
	 *
	 * @return 返回本周结束时间
	 */
	private static TemporalAdjuster getLastTemporalAdjuster() {
		return TemporalAdjusters.ofDateAdjuster(
				localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
	}

	/**
	 * 获取月份
	 *
	 * @param month
	 *            月份
	 * @return 数值
	 */
	private static int getMonth(final Month month) {
		return month.getValue();
	}

	/**
	 * 演示
	 *
	 * @param args
	 *            参数
	 */
	public static void main(final String[] args) {
		System.out.println("========= Instant");
		final Instant instant = Instant.now(); //获取当前时间戳
		System.out.println(instant);

		final ZonedDateTime zonedDateTime = ZonedDateTime.now(); //获取带有时区的时间
		System.out.println("========= ZonedDateTime");
		System.out.println(zonedDateTime);

		System.out.println("========= LocalDate");
		final LocalDate localDate = LocalDate.now(); //获取当前日期
		System.out.println(localDate);
		System.out.println(LocalDateUtil.dateToStr(localDate, LocalDateUtil.DEFAULT_PATTERN_DATE_CHINESE));
		System.out.println(LocalDateUtil.dateToStr(localDate, "uuMMdd"));
		System.out.println("取得指定日期的前一天：" + LocalDateUtil.dateToStr(LocalDateUtil.getPreviousDay(localDate)));

		System.out.println("========= LocalTime");
		final LocalTime localTime = LocalTime.now(); //获取当前时刻
		System.out.println(localTime);
		System.out.println(LocalDateUtil.timeToStr(localTime, LocalDateUtil.DEFAULT_PATTERN_TIME));

		System.out.println("========= LocalDateTime");
		final LocalDateTime localDateTime = LocalDateTime.now(); //获取当前具体时间
		System.out.println(localDateTime);
		System.out.println(LocalDateUtil.dateTimeToStr(localDateTime));
		System.out.println(LocalDateUtil.dateTimeToStr(localDateTime, LocalDateUtil.DEFAULT_PATTERN_DATE));
		System.out.println("取得指定时间的前一天：" + LocalDateUtil.dateTimeToStr(LocalDateUtil.getPreviousDay(localDateTime)));
		System.out.println("+ 1 天 ：" + LocalDateUtil
				.dateTimeToStr(LocalDateUtil.addDays(LocalDateUtil.dateTimeToInstant(localDateTime), 1)));
		System.out.println("+ 3 小时 ：" + LocalDateUtil
				.dateTimeToStr(LocalDateUtil.addHours(LocalDateUtil.dateTimeToInstant(localDateTime), 3)));

		// 当前毫秒数
		System.out.println(LocalDateUtil.getMillis(localDateTime));

		System.out.println("========= showTime");
		System.out.println(LocalDateUtil.showTime(LocalDateUtil.strToDateTime("2020-07-06 11:04:22")));
		System.out.println(LocalDateUtil.showTime(LocalDateUtil.strToDateTime("2020-07-01 11:04:22")));
		System.out.println(LocalDateUtil.showTime(LocalDateUtil.strToDateTime("2019-03-01 11:04:22")));

		System.out.println("========= checkDate");
		System.out.println(LocalDateUtil.checkDate(LocalDateUtil.strToDate("2020-05-01"), LocalDate.now()));

		System.out.println("========= checkTime");
		System.out.println(
				LocalDateUtil.checkTime(LocalDateTime.now(), LocalDateUtil.strToDateTime("2020-07-01 11:04:22")));
		System.out.println(
				LocalDateUtil.checkTime(LocalDateUtil.strToDateTime("2020-07-02 11:04:22"), LocalDateTime.now()));

		System.out.println("========= Timestamp");
		final Timestamp time = Timestamp.from(Instant.now());
		//      一、java.sql.Timestamp 转 java.time.LocalDateTime
		final LocalDateTime localDateTime2 = time.toLocalDateTime();
		System.out.println("转换后时间3:" + localDateTime2);
		//      二、java.time.LocalDateTime 转 java.sql.Timestamp
		final Timestamp time2 = Timestamp.valueOf(localDateTime);
		System.out.println("转换后时间4:" + time2);

	}
}